package com.panopset.swing;

import static com.panopset.Util.dump;
import static com.panopset.Util.x;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import com.panopset.Util;
import com.panopset.gui.Favicon;
import com.panopset.gui.PopupBox;
import com.panopset.gui.TPanel;
import com.panopset.gui.TypicalDialog;
import com.panopset.gui.container.PanTextField;
import com.panopset.swing.FontManager.Size;

/**
 * Application frame that provides document to GUI scaffolding.
 *
 * @author Karl Dinwiddie
 *
 */
public abstract class App {

//    /**
//     * @return True if this is a database enabled application.
//     */
//    public boolean hasH2() {
//        return false;
//    }

    public static App app;
    /**
     * @param favicon
     *            Frame 16x16 favicon.
     */
    public App(
            final Favicon favicon) {
        app = this;
        icon = favicon;
        f = new SimpleFrame();
    }


    /**
     * Not used except for tests, you'll want to use the constructor which takes
     * an Favicon.
     */
    public App() {
        this(null);
    }

    public static void main(String... s) throws Exception {
        new App() {

            @Override
            public Component createMainPanel() {
                TPanel p = new TPanel();
                PanTextField tf = new PanTextField(20, "test", "test");
                p.add(tf.getPanel());
                return p;
            }

            @Override
            protected PopupBox getAboutBox() {
                return new PopupBox(new TPanel(), new Dimension(40, 40),
                        f.getFrame());
            }

            @Override
            public final String getApplicationName() {
                return "TestApp";
            }

        }.show();
    }

    /**
     * @return Image or null if not set.
     */
    public static final Image getIcon() {
        if (app == null) {
            return null;
        }
        if (app.icon == null) {
            return null;
        }
        if (app.icon.getImageResource() == null) {
            return null;
        }
        return app.icon.getImageResource().getImage();
    }

    public void quit() {
        f.quit();
        Scaffolding.s.flush();
        Osgw.close();
        //H2Util.close();
    }

    public void show() {
        Scaffolding.s.load();
        f.getFrame().setTitle(Util.getCanonicalPath(Scaffolding.s.getHome()));
        String size = Scaffolding.s.get(FontManager.KEY);
        if (size != null) {
            FontManager.getInstance().setSize(size);
        }
        f.getFrame().validate();
        f.show();
        Field.synch();
    }

    /**
     * Simple frame.
     */
    public final SimpleFrame f;

    /**
     * Favicon.
     */
    public Favicon icon;

    protected abstract PopupBox getAboutBox();

    /**
     * Menu bar.
     */
    private JMenuBar mb;

    /**
     * @return Menu bar.
     */
    public JMenuBar getMenuBar() {
        if (mb == null) {
            mb = new MessageMenuBar();
            mb.add(createFileMenu());
            mb.add(createFontMenu());
//            if (hasH2()) {
//                mb.add(createDataMenu());
//            }
            mb.add(createHelpMenu());
        }
        return mb;
    }

    /**
     * Override to add menus in between the File and Help menus.
     *
     * @param menuBar
     *            Menu bar.
     */
    protected void addMiddleMenus(final JMenuBar menuBar) {
        // Nothing to do for default behavior.
    }

    /**
     * Show about box.
     */
    public final synchronized void doAbout() {
        getAboutBox().show();
    }

    /**
     * Do system info.
     */
    public final synchronized void doSystemInfo() {
        new TypicalDialog.Builder(x("System Information")).centerPanel(
                new SysInfoPanel().getGui()).construct().display();
    }

    /**
     * Do Java Properties.
     */
    public final synchronized void doEnvInfo() {
        TypicalDialog.dspdlg("System Environment Variables", dump(System
                .getenv()));
    }

    /**
     * Do Java Properties.
     */
    public final synchronized void doJavaProperties() {
        TypicalDialog.dspdlg("Java System Properties", dump(System
                .getProperties()));
    }

    /**
     * Do show log.
     */
    public final synchronized void doShowLog() {
        TypicalDialog.dspdlg("Log", com.panopset.Util.getLog());
    }

    /**
     * Application name.
     */
    private String applicationName;

    /**
     * @return Application name.
     */
    public String getApplicationName() {
        if (applicationName == null) {
            applicationName = this.getClass().getSimpleName();
        }
        return applicationName;
    }

    /**
     * Use this if you don't want the simple class name to be the Application
     * name.
     *
     * @param newName
     *            New application name.
     */
    public final void setApplicationName(final String newName) {
        applicationName = newName;
    }

    /**
     * @return help menu.
     */
    private JMenu createHelpMenu() {
        JMenu menu = new JMenu("Help");
        menu.setMnemonic(KeyEvent.VK_H);
        FontManager.register(menu,
               FontManager.FontType.plainArial);

        JMenuItem mi = new JMenuItem(x("About") + " " + getApplicationName());
        mi.setMnemonic(KeyEvent.VK_A);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                doAbout();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem(x("Java Properties"));
        mi.setMnemonic(KeyEvent.VK_J);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                doJavaProperties();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem(x("System Information"));
        mi.setMnemonic(KeyEvent.VK_J);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                doSystemInfo();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem(x("Environment Variables"));
        mi.setMnemonic(KeyEvent.VK_E);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                doEnvInfo();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem(x("Log"));
        mi.setMnemonic(KeyEvent.VK_J);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                doShowLog();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        return menu;
    }

    /**
     * @param size
     *            Size.
     */
    private void setSize(final Size size) {
        FontManager.getInstance().setSize(size);
        Scaffolding.s.put(FontManager.KEY, "" + size.getValue());
    }

    /**
     * @return file menu.
     */
    private JMenu createFontMenu() {
        JMenu menu = new JMenu("Font");
        for (final FontManager.Size size : FontManager.Size.values()) {
            JMenuItem mi = size.getMenuItem();
            mi.addActionListener(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    setSize(size);
                }
            });
            FontManager.register(mi,
                   FontManager.FontType.plainArial);
            menu.add(mi);
        }
        FontManager.register(menu,
               FontManager.FontType.plainArial);
        return menu;
    }

    /**
     * @return file menu.
     */
    private JMenu createDataMenuMOVE() {
        JMenu menu = new JMenu("Data");

        JMenuItem mi = new JMenuItem(x("Reset"));
        mi.setMnemonic(KeyEvent.VK_N);
        mi.setToolTipText(x("Reset data to defaults."));
        mi.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                //H2Util.reset();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem(x("Debug H2"));
        mi.setMnemonic(KeyEvent.VK_N);
        mi.setToolTipText(x("Launch the H2 server to analyze data."));
        mi.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                //H2Util.startServer();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem(x("info"));
        mi.setMnemonic(KeyEvent.VK_N);
        mi.setToolTipText(x("Show database information."));
        mi.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
//                TypicalDialog.dspdlg("H2 Database Information",
//                        H2Util.showInfo());
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        FontManager.register(menu,
               FontManager.FontType.plainArial);
        return menu;
    }

    /**
     * @return file menu.
     */
    private JMenu createFileMenu() {
        JMenu menu = new JMenu("File");
        menu.setMnemonic(KeyEvent.VK_F);
        FontManager.register(menu,
               FontManager.FontType.plainArial);

        JMenuItem mi = new JMenuItem("New");
        mi.setMnemonic(KeyEvent.VK_N);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                Scaffolding.s.doNew();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem("Open");
        mi.setMnemonic(KeyEvent.VK_O);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                Scaffolding.s.doOpen();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem("Save");
        mi.setMnemonic(KeyEvent.VK_S);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                Scaffolding.s.doSave();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem("Save as");
        mi.setMnemonic(KeyEvent.VK_A);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                Scaffolding.s.doSaveAs();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem("Reset");
        mi.setToolTipText(
            x("Reset all fields to defaults, set window to default size."));
        mi.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                Scaffolding.s.reset();
                App.app.f.getFrame().setSize(SimpleFrame.DEFAULT_SIZE);
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        mi = new JMenuItem("Quit");
        mi.setMnemonic(KeyEvent.VK_Q);
        mi.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                quit();
            }
        });
        FontManager.register(mi, FontManager.FontType.plainArial);
        menu.add(mi);

        return menu;
    }

    /**
     * @return Main panel.
     */
    public abstract Component createMainPanel();
}
